﻿using System;
using System.Linq;
using Microsoft.Practices.Unity;
using DeveloperModule.ViewModels;
using TimeSplicerModule.Services;
using TimeSplicerModule.Security;
using TimeSplicerModule.DomainModels;
using TimeSplicerModule.ViewModels;
using TimeSplicerModule.Factories;

namespace DeveloperModule.Services
{
    public interface IDeveloperService
    {
        UserSelectionViewModel GetUserSelectionViewModel();
        void ChangeSessionUser(UserModel user);
        void FixTaskCompletedDate();
        void FixTaskStartedDate();
        void UpdateActualHoursForProjectsAndTasks();
    }

    public class DeveloperService : IDeveloperService
    {
        private readonly IUnityContainer _container;
        private ISession _session;
        private readonly IUserService _userService;
        private readonly ISessionService _sessionService;
        private readonly IProjectFactory _projectFactory;
        private readonly ITaskFactory _taskFactory;
        private readonly ITimestampFactory _timestampFactory;
        private readonly IStatusFactory _statusFactory;

        public DeveloperService(IUnityContainer container, IUserService userService, ISessionService sessionService, IProjectFactory projectFactory, ITaskFactory taskFactory, ITimestampFactory timestampFactory, IStatusFactory statusFactory)
        {
            _container = container;
            _userService = userService;
            _sessionService = sessionService;
            _projectFactory = projectFactory;
            _taskFactory = taskFactory;
            _timestampFactory = timestampFactory;
            _statusFactory = statusFactory;
        }

        public UserSelectionViewModel GetUserSelectionViewModel()
        {
            _session = _container.Resolve<ISession>();
            var model = new UserSelectionViewModel();

            model.Users = _userService.GetViewableUsers();
            model.SelectedUserGuid = model.Users.FirstOrDefault().UserGuid;

            return model;
        }


        public void ChangeSessionUser(UserModel user)
        {
            _session = _container.Resolve<ISession>();
            var newSession = _sessionService.Get(user.Login);

            _session.User = newSession.User;
        }

        public void FixTaskCompletedDate()
        {
            var completed = _statusFactory.Get(x => x.StatusEnum == Infrastucture.Status.Completed.ToString());

            var tasks = _taskFactory.GetList(x => x.StatusGuid == completed.StatusGuid);
            
            foreach (var t in tasks)
            {
                var stamps = _timestampFactory.GetList(x => x.TaskGuid == t.TaskGuid);
                var last = stamps.OrderByDescending(x => x.StampNumber).FirstOrDefault();

                if (last != null)
                {
                    t.CompletedDate = last.EndTime;
                    _taskFactory.Upsert(t);
                }
            }
        }


        public void FixTaskStartedDate()
        {
            var tasks = _taskFactory.GetList(x => x.StartedDate == DateTime.MinValue);

            foreach (var t in tasks)
            {
                var stamp = _timestampFactory.Get(x => x.TaskGuid == t.TaskGuid
                    && x.StampNumber == 1);

                if (stamp != null)
                {
                    t.StartedDate = stamp.StartTime;
                    _taskFactory.Upsert(t);
                }
            }
        }


        // Next need method that aggregates all time
        public void UpdateActualHoursForProjectsAndTasks()
        {
            var projects = _projectFactory.GetList();

            foreach (var p in projects)
            {
                double projectHours = 0D;
                var tasks = _taskFactory.GetList(x => x.ProjectGuid == p.ProjectGuid);

                foreach (var t in tasks)
                {
                    var taskHours = 0D;

                    var stamps = _timestampFactory.GetList(x => x.TaskGuid == t.TaskGuid);

                    if (stamps.Count > 0)
                    {
                        taskHours += stamps.Sum(x => x.Hours);
                        projectHours += taskHours;

                        t.ActualHours = taskHours;
                        _taskFactory.Upsert(t);
                    }
                }

                if (projectHours > 0)
                {
                    p.ActualHours = projectHours;
                    _projectFactory.Upsert(p);
                }
            }
        }
    }
}
